package com.unittec.zk.provider.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.unittec.zk.sdk.root.common.CommonConstant;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p>
 * 文件操作工具类
 * <p>
 *
 * @author wuxinwei
 * @version 1.0
 */
@SuppressWarnings({"resource", "unused"})
public class FileUtils {

    /**
     * 获取windows/linux的项目根目录
     *
     * @return
     */
    public static String getConTextPath() {
        String fileUrl = Thread.currentThread().getContextClassLoader().getResource("").getPath();
        if (CommonConstant.STR_USR.equals(fileUrl.substring(CommonConstant.SIZE_1, CommonConstant.SIZE_4))) {
            // linux
            fileUrl = (fileUrl.substring(CommonConstant.SIZE_0, fileUrl.length() - CommonConstant.SIZE_16));
        } else {
            // windows
            fileUrl = (fileUrl.substring(CommonConstant.SIZE_1, fileUrl.length() - CommonConstant.SIZE_16));
        }
        return fileUrl;
    }

    /**
     * 字符串转数组
     *
     * @param str      字符串
     * @param splitStr 分隔符
     * @return
     */
    public static String[] stringToArray(String str, String splitStr) {
        String[] arrayStr = null;
        if (!"".equals(str) && str != null) {
            if (str.indexOf(splitStr) != -1) {
                arrayStr = str.split(splitStr);
            } else {
                arrayStr = new String[1];
                arrayStr[0] = str;
            }
        }
        return arrayStr;
    }

    /**
     * 读取文件
     *
     * @param path
     * @return
     */
    public static String readFile(String path) {
        BufferedReader reader = null;
        String laststr = "";
        try {
            FileInputStream fileInputStream = new FileInputStream(path);
            InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
            reader = new BufferedReader(inputStreamReader);
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {
                laststr += tempString;
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return laststr;
    }

    /**
     * 获取文件夹下所有文件的名称 + 模糊查询（当不需要模糊查询时，queryStr传空或null即可） 1.当路径不存在时，map返回retType值为1
     * 2.当路径为文件路径时，map返回retType值为2，文件名fileName值为文件名 3.当路径下有文件夹时，map返回retType值为3，文件名列表fileNameList，文件夹名列表folderNameList
     *
     * @param folderPath 路径
     * @param queryStr   模糊查询字符串
     * @return
     */
    public static HashMap<String, Object> getFilesName(String folderPath, String queryStr) {
        HashMap<String, Object> map = new HashMap<>();
        // 文件名列表
        List<String> fileNameList = new ArrayList<>();
        // 文件夹名列表
        List<String> folderNameList = new ArrayList<>();
        File f = new File(folderPath);
        // 路径不存在
        if (!f.exists()) {
            map.put("retType", "1");
        } else {
            boolean flag = f.isDirectory();
            // 路径为文件
            if (!flag) {
                map.put("retType", "2");
                map.put("fileName", f.getName());
            } else { // 路径为文件夹
                map.put("retType", "3");
                File[] fa = f.listFiles();
                // 若queryStr传入为null,则替换为空（indexOf匹配值不能为null）
                queryStr = queryStr == null ? "" : queryStr;
                if (fa != null && fa.length > 0) {
                    for (File fs : fa) {
                        if (fs.getName().contains(queryStr)) {
                            if (fs.isDirectory()) {
                                folderNameList.add(fs.getName());
                            } else {
                                fileNameList.add(fs.getName());
                            }
                        }
                    }
                }
                map.put("fileNameList", fileNameList);
                map.put("folderNameList", folderNameList);
            }
        }
        return map;
    }

    /**
     * 以行为单位读取文件，读取到最后一行
     *
     * @param filePath
     * @return
     */
    public static List<String> readFileContent(String filePath) {
        List<String> listContent = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String tempString = null;
            int line = 1;
            // 一次读入一行，直到读入null为文件结束
            while ((tempString = reader.readLine()) != null) {
                listContent.add(tempString);
                line++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return listContent;
    }

    /**
     * 读取指定行数据 ，注意：0为开始行
     *
     * @param filePath
     * @param lineNumber
     * @return
     */
    public static String readLineContent(String filePath, int lineNumber) {
        String lineContent = "";
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            int line = 0;
            while (line <= lineNumber) {
                lineContent = reader.readLine();
                line++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return lineContent;
    }

    /**
     * 读取从beginLine到endLine数据（包含beginLine和endLine），注意：0为开始行
     *
     * @param filePath
     * @param beginLineNumber 开始行
     * @param endLineNumber   结束行
     * @return
     */
    public static List<String> readLinesContent(String filePath, int beginLineNumber, int endLineNumber) {
        List<String> listContent = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            int count = 0;
            String content = reader.readLine();
            while (content != null) {
                if (count >= beginLineNumber && count <= endLineNumber) {
                    listContent.add(content);
                }
                content = reader.readLine();
                count++;
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return listContent;
    }

    /**
     * 读取若干文件中所有数据
     *
     * @param listFilePath
     * @return
     */
    public static List<String> readFileContentList(List<String> listFilePath) {
        List<String> listContent = new ArrayList<>();
        for (String filePath : listFilePath) {
            File file = new File(filePath);
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader(file));
                String tempString = null;
                int line = 1;
                // 一次读入一行，直到读入null为文件结束
                while ((tempString = reader.readLine()) != null) {
                    listContent.add(tempString);
                    line++;
                }
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e1) {
                    }
                }
            }
        }
        return listContent;
    }

    /**
     * 文件数据写入（如果文件夹和文件不存在，则先创建，再写入）
     *
     * @param filePath
     * @param content
     * @param flag     true:如果文件存在且存在内容，则内容换行追加；false:如果文件存在且存在内容，则内容替换
     */
    public static String fileLinesWrite(String filePath, String content, boolean flag) {
        String filedo = "write";
        FileWriter fw = null;
        try {
            File file = new File(filePath);
            // 如果文件夹不存在，则创建文件夹
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            if (!file.exists()) {// 如果文件不存在，则创建文件,写入第一行内容
                file.createNewFile();
                fw = new FileWriter(file);
                filedo = "create";
            } else {// 如果文件存在,则追加或替换内容
                fw = new FileWriter(file, flag);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        PrintWriter pw = new PrintWriter(fw);
        pw.println(content);
        pw.flush();
        try {
            fw.flush();
            pw.close();
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return filedo;
    }

    /**
     * 写文件
     *
     * @param ins
     * @param out
     */
    public static void writeIntoOut(InputStream ins, OutputStream out) {
        byte[] bb = new byte[10 * 1024];
        try {
            int cnt = ins.read(bb);
            while (cnt > 0) {
                out.write(bb, 0, cnt);
                cnt = ins.read(bb);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                out.flush();
                ins.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 判断list中元素是否完全相同（完全相同返回true,否则返回false）
     *
     * @param list
     * @return
     */
    private static boolean hasSame(List<? extends Object> list) {
        if (null == list) {
            return false;
        }
        return 1 == new HashSet<Object>(list).size();
    }

    /**
     * 判断list中是否有重复元素（无重复返回true,否则返回false）
     *
     * @param list
     * @return
     */
    private static boolean hasSame2(List<? extends Object> list) {
        if (null == list) {
            return false;
        }
        return list.size() == new HashSet<Object>(list).size();
    }

    /**
     * 增加/减少天数
     *
     * @param date
     * @param num
     * @return
     */
    public static Date dateAddOrSub(Date date, int num) {
        Calendar startDt = Calendar.getInstance();
        startDt.setTime(date);
        startDt.add(Calendar.DAY_OF_MONTH, num);
        return startDt.getTime();
    }
    // https://www.cnblogs.com/chenhuan001/p/6575053.html

    /**
     * 递归删除文件或者目录
     *
     * @param filePath
     */
    public static void deleteEveryThing(String filePath) {
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                return;
            }
            if (file.isFile()) {
                file.delete();
            } else {
                File[] files = file.listFiles();
                for (int i = 0; i < files.length; i++) {
                    String root = files[i].getAbsolutePath();// 得到子文件或文件夹的绝对路径
                    deleteEveryThing(root);
                }
                file.delete();
            }
        } catch (Exception e) {
            System.out.println("删除文件失败");
        }
    }

    /**
     * 创建目录
     *
     * @param dirPath
     */
    public static void mkDir(String dirPath) {
        File myFolderPath = new File(dirPath);
        try {
            if (!myFolderPath.exists()) {
                myFolderPath.mkdir();
            }
        } catch (Exception e) {
            System.out.println("新建目录操作出错");
            e.printStackTrace();
        }
    }

    // https://blog.csdn.net/lovoo/article/details/77899627

    /**
     * 判断指定的文件是否存在。
     *
     * @param fileName
     * @return
     */
    public static boolean isFileExist(String fileName) {
        return new File(fileName).isFile();
    }

    /**
     * 得到文件后缀名
     *
     * @param fileName
     * @return
     */
    public static String getFileExt(String fileName) {
        int point = fileName.lastIndexOf('.');
        int length = fileName.length();
        if (point == -1 || point == length - 1) {
            return "";
        } else {
            return fileName.substring(point + 1, length);
        }
    }

    /**
     * 删除文件夹及其下面的子文件夹
     *
     * @param dir
     * @throws IOException
     */
    public static void deleteDir(File dir) throws IOException {
        if (dir.isFile()) {
            throw new IOException("IOException -> BadInputException: not a directory.");
        }
        File[] files = dir.listFiles();
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                File file = files[i];
                if (file.isFile()) {
                    file.delete();
                } else {
                    deleteDir(file);
                }
            }
        }
        dir.delete();
    }

    /**
     * 复制文件
     *
     * @param src
     * @param dst
     * @throws Exception
     */
    public static void copy(File src, File dst) throws Exception {
        int bufferSize = 4096;
        InputStream in = null;
        OutputStream out = null;
        try {
            in = new BufferedInputStream(new FileInputStream(src), bufferSize);
            out = new BufferedOutputStream(new FileOutputStream(dst), bufferSize);
            byte[] buffer = new byte[bufferSize];
            int len = 0;
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                in = null;
            }
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                out = null;
            }
        }
    }

    /**
     * 获取文件夹和文件夹下的子文件夹的文件路径
     *
     * @param unZipFileDir
     * @return
     */
    public static List<JSONObject> getDirFilePath(String unZipFileDir) {
        File unZipFile = new File(unZipFileDir);
        File[] listFile = unZipFile.listFiles();

        List<JSONObject> list = new ArrayList<>();

        for (File rootDir : listFile) {
            if (!rootDir.isFile()) {
                JSONObject json = new JSONObject();
                JSONArray array = new JSONArray();
                String rootPath = rootDir.getPath();
                String rootName = rootDir.getName();
                File[] picListFile = rootDir.listFiles();
                for (File subFile : picListFile) {
                    if (subFile.isFile()) {
                        String subFilePath = subFile.getPath();
                        String subFileName = subFile.getName();
                        JSONObject subJson = new JSONObject();
                        subJson.put("subFilePath", subFilePath);
                        subJson.put("subFileName", subFileName);
                        subJson.put("fileSize", subFile.length());
                        array.add(subJson);
                    }
                }
                json.put("rootName", rootName);
                json.put("rootPath", rootPath);
                json.put("subPath", array);
                json.put("fileSize", rootDir.length());
                list.add(json);
            }
        }
        return list;
    }

    /**
     * 获取文件大小
     *
     * @param size
     * @return
     */
    public static String getFileSize(long size) {
        // 如果字节数少于1024，则直接以B为单位，否则先除于1024，后3位因太少无意义
        if (size < 1024) {
            return size + "B";
        } else {
            size = size / 1024;
        }
        // 如果原字节数除于1024之后，少于1024，则可以直接以KB作为单位
        // 因为还没有到达要使用另一个单位的时候
        // 接下去以此类推
        if (size < 1024) {
            return size + "KB";
        } else {
            size = size / 1024;
        }
        if (size < 1024) {
            // 因为如果以MB为单位的话，要保留最后1位小数，
            // 因此，把此数乘以100之后再取余
            size = size * 100;
            return size / 100 + "." + size % 100 + "MB";
        } else {
            // 否则如果要以GB为单位的，先除于1024再作同样的处理
            size = size * 100 / 1024;
            return size / 100 + "." + size % 100 + "GB";
        }
    }

    /**
     * 判断是否是图片
     *
     * @param fileName
     * @return
     */
    public static boolean getImageType(String fileName) {
        // 文件的后缀名
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        if (".bmp".equalsIgnoreCase(fileExtension)) {
            return true;
        } else if (".gif".equalsIgnoreCase(fileExtension)) {
            return true;
        } else if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
                || ".png".equalsIgnoreCase(fileExtension)) {
            return true;
        } else {
            return ".png".equalsIgnoreCase(fileExtension);
        }
    }

    /**
     * 判断是否是视频
     *
     * @param fileName
     * @return
     */
    public static boolean getVideoType(String fileName) {
        // 文件的后缀名
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        if (".AVI".equalsIgnoreCase(fileExtension)) {
            return true;
        } else if (".mp4".equalsIgnoreCase(fileExtension)) {
            return true;
        } else if (".MPEG".equalsIgnoreCase(fileExtension) || ".rmvb".equalsIgnoreCase(fileExtension)
                || ".WMV".equalsIgnoreCase(fileExtension)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 判断是否含有特殊字符 _ - . 可以包含在内
     *
     * @param str
     * @return
     */
    public static boolean checkSpecialStr(String str) {
        String regEx = "[ `~!@#$%^&*+=|{}':;',\\[\\]<>/?~！@#￥%……&*——+|{}【】‘；：”“’。，、？]|\n|\r|\t";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        return m.find();
    }


    public static File multipartFileToFile(MultipartFile file) throws Exception {

        File toFile = null;
        if (null == file || file.getSize() <= 0) {
            file = null;
        } else {
            InputStream ins = null;
            ins = file.getInputStream();
            toFile = new File(file.getOriginalFilename());
            inputStreamToFile(ins, toFile);
            ins.close();
        }
        return toFile;
    }

    // 获取流文件
    private static void inputStreamToFile(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 图片格式判断
     *
     * @param prefix
     * @return
     */
    public static boolean imageType(String prefix) {
        if (prefix.equalsIgnoreCase("JPG") || prefix.equalsIgnoreCase("JPEG") || prefix.equalsIgnoreCase("GIF")
                || prefix.equalsIgnoreCase("PNG") || prefix.equalsIgnoreCase("BMP") || prefix.equalsIgnoreCase("PCX")
                || prefix.equalsIgnoreCase("TGA") || prefix.equalsIgnoreCase("PSD") || prefix.equalsIgnoreCase("TIFF")) {
            return true;
        } else {
            return false;
        }

    }


    /**
     * 音频格式判断
     *
     * @param prefix
     * @return
     */
    public static boolean audioType(String prefix) {
        if (prefix.equalsIgnoreCase("mp3") || prefix.equalsIgnoreCase("OGG") || prefix.equalsIgnoreCase("WAV")
                || prefix.equalsIgnoreCase("REAL") || prefix.equalsIgnoreCase("APE") || prefix.equalsIgnoreCase("MODULE")
                || prefix.equalsIgnoreCase("MIDI") || prefix.equalsIgnoreCase("VQF") || prefix.equalsIgnoreCase("CD")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 视频格式判断
     *
     * @param prefix
     * @return
     */
    public static boolean videoType(String prefix) {
        if (prefix.equalsIgnoreCase("mp4") || prefix.equalsIgnoreCase("avi") || prefix.equalsIgnoreCase("MPEG-1")
                || prefix.equalsIgnoreCase("RM") || prefix.equalsIgnoreCase("ASF") || prefix.equalsIgnoreCase("WMV")
                || prefix.equalsIgnoreCase("qlv") || prefix.equalsIgnoreCase("MPEG-2") || prefix.equalsIgnoreCase("MPEG4")
                || prefix.equalsIgnoreCase("mov") || prefix.equalsIgnoreCase("3gp")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 判断文件夹是否存在
     *
     * @param file
     */
    public static void judeDirExists(File file) {
        File dir = file.getParentFile();
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try {
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
